/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package xenon3d.scene;

import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureData;
import com.jogamp.opengl.util.texture.TextureIO;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.media.opengl.GL2;
import xenon3d.Xenon3D;

/**
 * The Texture2D attribute is a component of an Appearance object that defines the
 * texture properties used when texture mapping is enabled.
 *
 * @author Volker Everts
 * @version 0.1 - 18.11.2011: Created
 */
public class Texture2D extends Attributes {

    // <editor-fold defaultstate="collapsed" desc=" Static Attributes ">

    /** The default Texture2D. */
    static final Texture2D DEFAULT = new Texture2D();

    /** The last active texture object. */
    private static Texture2D last = DEFAULT;

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Private Fields ">

    /** The internal JOGL texture data. */
    private TextureData data;

    /** The internal JOGL texture object. */
    private Texture tex;

    /** The texture attributes object. */
    private TextureAttributes attr;

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Initialization ">

    // Static Initializer
    {
        TextureIO.setTexRectEnabled(false);
    }

    /**
     * Creates a new empty Texture2D.
     */
    public Texture2D() {

    }

    /**
     * Creates a new Texture2D based on the specified TextureData object.
     * @param data the TextureData object
     */
    public Texture2D(TextureData data) {
        this.data = data;
    }

    /**
     * Creates a new Texture2D object by loading it from the given file.
     * @param file the texture file
     * @param mipmap if true, mipmaps will be created automatically
     * @param format the file format of the texture file
     * @return the loaded texture
     * @throws IOException if an I/O error occours during loading
     */
    public static Texture2D loadTexture(File file, boolean mipmap, FileFormat format) throws IOException {
        return new Texture2D(TextureIO.newTextureData(Xenon3D.getProfile(), file, mipmap, format.value()));
    }

    /**
     * Creates a new Texture2D object by reading it from the given input stream.
     * @param in the input stream to read from
     * @param mipmap if true, mipmaps will be created automatically
     * @param format the file format of the texture file
     * @return the loaded texture
     * @throws IOException if an I/O error occours during loading
     */
    public static Texture2D loadTexture(InputStream in, boolean mipmap, FileFormat format) throws IOException {
        return new Texture2D(TextureIO.newTextureData(Xenon3D.getProfile(), in, mipmap, format.value()));
    }

    /**
     * Creates a new Texture2D by loading it from the given URL.
     * @param url the url from which to load the texture
     * @param mipmap if true, mipmaps will be created automatically
     * @param format the file format of the texture file
     * @return the loaded texture
     * @throws IOException if an I/O error occours during loading
     */
    public static Texture2D loadTexture(URL url, boolean mipmap, FileFormat format) throws IOException {
        return new Texture2D(TextureIO.newTextureData(Xenon3D.getProfile(), url, mipmap, format.value()));
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Public Properties ">

    /**
     * Returns the internal texture data object.
     * @return the texture data
     */
    public final TextureData getTextureData() {
        return data;
    }

    /**
     * Returns whether or not texture coordinates must be flipped vertically
     * when using this texture data contained in this Texture2D.
     * @return true, if texture coordinates must be flipped
     */
    public final boolean mustFlipVertically() {
        if (data == null) return false;
        return data.getMustFlipVertically();
    }

    /**
     * Sets the texture attributes for this Texture2D.
     * @param attr the new texture attributes
     */
    public final void setTextureAttributes(TextureAttributes attr) {
        checkCapability(Capability.AllowTextureAttributesWrite);
        if (attr == null) attr = TextureAttributes.DEFAULT;
        if (attr == this.attr) return;
        this.attr.removeNotify(this);
        attr.addNotify(this);
        this.attr = attr;
    }

    /**
     * Returns the texture attributes for this Texture2D.
     * @return the texture attributes
     */
    public final TextureAttributes getTextureAttributes() {
        if (attr == TextureAttributes.DEFAULT) return null;
        return attr;
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Package Private Methods (OpenGL) ">

    @Override
    void apply(GL2 gl) {
        if (this == last) return;
        if (tex == null) {
            if (data == null) tex = new Texture(GL2.GL_TEXTURE_2D);
            else tex = new Texture(data);
        }
	if (data != last.data) {
            if (last.data == null) tex.enable();
            else if (data == null) tex.disable();
            tex.bind();
	}
        if (attr != last.attr) attr.apply(gl);
        last = this;
    }

    // </editor-fold>

} // end class Texture2D